home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_400
/
432_01
/
ptmid3
/
samples.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-07-01
|
7KB
|
280 lines
/*
* samples.c: Routines for Ptmid to deal with samples. The use of these
* routines makes it easy to add support for further sample formats.
*
* author: Andrew Scott (c)opyright 1994
*
* date: 30/6/1994
*/
#include <stdio.h>
#include <string.h>
#include "ptmid.h"
#include "samples.h"
/** Define VC enumerated type to specify sort of VOC-chunk to look for **/
enum VC { VC_term = 0, VC_voc, VC_cnt, VC_spc, VC_mrk, VC_txt,
VC_rep, VC_enr };
/*
* CatFn: Given two filenames, will return a pointer to a copy of them
* concatenated together.
*
* date: 30/6/1994
*/
Sz CatFn(Sz fnA, Sz fnB)
{
static Fn fnBuff;
Sz szT = fnBuff;
while (*szT = *(fnA++))
szT++;
while (*(szT++) = *(fnB++));
return fnBuff;
}
/*
* FIsvoc: Given a file pointer, will return NZ if the file is a VOC
* file.
*
* date: 30/6/1994
*/
int FIsvoc(FILE *pfile)
{
char rgbClbuff[20];
fseek(pfile, 0, SEEK_SET);
if (fread(rgbClbuff, 20, 1, pfile) == 0)
return 0;
return !strncmp(rgbClbuff, "Creative Voice File\32", 20);
}
/*
* FIswav: Given a file pointer, will return NZ if the file is a WAV
* file.
*
* date: 1/7/1994
*/
int FIswav(FILE *pfile)
{
char rgbRiffbuff[12];
fseek(pfile, 0, SEEK_SET);
if (fread(rgbRiffbuff, 12, 1, pfile) == 0)
return 0;
return !strncmp(rgbRiffbuff, "RIFF", 4) &&
!strncmp(rgbRiffbuff + 8, "WAVE", 4);
}
/*
* LongRead: Returns the next long integer from the given file.
*
* date: 1/7/1994
*/
unsigned long LongRead(FILE *pfile)
{
unsigned long dw;
dw = getc(pfile);
dw += (unsigned long) getc(pfile) << 8;
dw += (unsigned long) getc(pfile) << 16;
dw += (unsigned long) getc(pfile) << 24;
return dw;
}
/*
* TriRead: Returns the next byte triple from the given file.
*
* date: 1/7/1994
*/
unsigned long TriRead(FILE *pfile)
{
unsigned long dw;
dw = getc(pfile);
dw += (unsigned long) getc(pfile) << 8;
dw += (unsigned long) getc(pfile) << 16;
return dw;
}
/*
* WordRead: Returns the next word from the given file.
*
* date: 1/7/1994
*/
unsigned WordRead(FILE *pfile)
{
unsigned w;
w = getc(pfile);
w += (unsigned) getc(pfile) << 8;
return w;
}
/*
* Govoc: Given a VOC-file and a chunk-tag, will advance the file to
* the start of the chunk if it exists and return NZ, else will return Z.
*
* date: 1/7/1994
*/
int Govoc(FILE *pfile, enum VC vcChunk)
{
int bT;
unsigned long len;
fseek(pfile, 20, SEEK_SET);
len = WordRead(pfile);
fseek(pfile, len, SEEK_SET);
bT = getc(pfile);
while (EOF != bT && 0 != bT && bT != vcChunk) {
len = TriRead(pfile);
if (0 < len)
fseek(pfile, len, SEEK_CUR);
bT = getc(pfile);
}
return bT == vcChunk;
}
/*
* Gowav: Given a wave-file and a chunk-name, will advance the file to
* the start of the chunk if it exists and return NZ, else will return Z.
*
* date: 1/7/1994
*/
int Gowav(FILE *pfile, Sz szChunk)
{
char rgbBuff[4];
unsigned long len;
fseek(pfile, 12, SEEK_SET);
fread(rgbBuff, 4, 1, pfile);
while (!feof(pfile) && strncmp(szChunk, rgbBuff, 4)) {
len = LongRead(pfile);
if (fseek(pfile, len, SEEK_CUR) || !fread(rgbBuff, 4, 1, pfile))
return 0;
}
return !feof(pfile);
}
/*
* FreqGetFn: Given a sample's filename, will return the frequency of
* that sample.
*
* date: 30/6/1994
*/
unsigned FreqGetFn(Sz fnSample)
{
unsigned freq = C2FREQUENCY;
int wData;
FILE *pfile;
pfile = fopen(CatFn(fnSampath, fnSample), "rb"); /** Open file **/
if (NULL != pfile) {
if (FIsvoc(pfile)) { /** If a VOC file **/
fseek(pfile, 20, SEEK_SET);
if ((wData = getc(pfile)) != EOF &&
!fseek(pfile, ((long) getc(pfile) << 8) | wData, SEEK_SET) &&
getc(pfile) == 1) { /*** Go to start of sound info ***/
getc(pfile); /*** Skip length ***/
getc(pfile);
getc(pfile);
wData = getc(pfile); /*** Get sample rate ***/
freq = (unsigned) (1000000L / (256 - wData));
}
} else if (FIswav(pfile) && Gowav(pfile, "fmt ")) { /** If a WAV file **/
fseek(pfile, 8, SEEK_CUR); /*** Go to position of freqency ***/
freq = (unsigned) LongRead(pfile); /*** Get sample rate ***/
}
fclose(pfile);
}
return freq;
}
/*
* LenOutPfileFn: Given an output file and a sample filename, writes the
* sample to the output file and returns the number of bytes written.
* If fSignout is NZ, data will be written in signed format, else in
* unsigned.
*
* date: 30/6/1994
* 1/7/1994 - added WAV format
* 2/7/1994 - added fSignout
*/
long LenOutPfileFn(FILE *pfileOut, Sz fnSample, int fSignout)
{
FILE *pfileSample;
long cSample = 0;
pfileSample = fopen(CatFn(fnSampath, fnSample), "rb");
if (NULL == pfileSample)
return 0;
if (FIsvoc(pfileSample)) { /** Is sample file a VOC file? **/
unsigned long cch;
int ch;
Govoc(pfileSample, VC_voc);
cch = TriRead(pfileSample) - 2; /*** Get length ***/
if (131072 < cch)
cch = 131072;
else if (cch & 1) /*** Ensure length is even ***/
cch &= ~1;
cSample = cch;
fseek(pfileSample, 2, SEEK_CUR); /*** Skip rate + compression ***/
while (cch-- && (ch = getc(pfileSample)) != EOF)
if (fSignout)
putc(ch ^ 128, pfileOut); /*** Copy the samples ***/
else
putc(ch, pfileOut);
} else if (FIswav(pfileSample)) { /** Is sample type WAV? **/
unsigned numchan, align, numbits, bytechan;
int ch;
unsigned long cch;
Gowav(pfileSample, "fmt ");
fseek(pfileSample, 6, SEEK_CUR);
numchan = WordRead(pfileSample); /*** Get #channels ***/
fseek(pfileSample, 8, SEEK_CUR);
align = WordRead(pfileSample); /*** Get block alignment (in bytes) ***/
numbits = WordRead(pfileSample); /*** Get #bits/sample ***/
bytechan = align / numchan; /*** Calc bytes/channel ***/
Gowav(pfileSample, "data");
cch = LongRead(pfileSample) / align;
if (131072 < cch)
cch = 131072;
else if (cch & 1) /*** Ensure length is even ***/
cch &= ~1;
cSample = cch;
while (cch--) { /*** With each sample.. ***/
if (1 < bytechan)
fseek(pfileSample, bytechan - 1, SEEK_CUR);
ch = getc(pfileSample); /*** Get most sig. byte ***/
if ((numbits > 8) == fSignout)
putc(ch, pfileOut); /*** Output it ***/
else
putc(ch ^ 128, pfileOut);
if (bytechan != align) /*** Skip any remaining channels of sample ***/
fseek(pfileSample, align - bytechan, SEEK_CUR);
}
} else { /** Sample file must be a SMP file **/
long cch;
int ch;
fseek(pfileSample, 0, SEEK_END);
cch = ftell(pfileSample);
if (131072 < cch)
cch = 131072;
else if (cch & 1) /** Ensure length is even **/
cch &= ~1;
cSample = cch;
fseek(pfileSample, 0, SEEK_SET);
while ((ch = getc(pfileSample)) != EOF)
if (fSignout)
putc(ch, pfileOut);
else
putc(ch ^ 128, pfileOut);
}
fclose(pfileSample);
return cSample;
}